'use strict';
const net = require('net');
const url = require('url');
const iac = require('iac');
const TIMEOUT = 100000;

function endSocket(socket) {
  socket.removeAllListeners('data').removeAllListeners('error');
  socket.destroy();
}

function formatHostPort(uri) {
  return url
    .format(uri)
    .replace(/^.+\/\//, '')
    .replace(/\/$/, '');
}

// dest = IP:port

module.exports = async function(dest, seq) {
  return new Promise((resolve, reject) => {
    const socket = new net.Socket();
    let interacting,
      saved = '',
      count = 1,
      index = 0,
      resultArr = [],
      reg = /-\s?More/gi,
      reg1 = /.\s?press/gi;

    dest = url.parse('http://' + dest);

    socket.setTimeout(TIMEOUT);

    socket.once('timeout', () => {
      console.log('timeout事件触发');
      endSocket(socket);
      reject(new Error('Timeout connecting to ' + formatHostPort(dest)));
    });

    socket.once('error', err => {
      console.log('发生了错误，即将关闭socket：', err);
      if (interacting) interacting = false;
      endSocket(socket);
      reject(err);
    });

    socket.on('connect', () => {
      // console.log(`与${dest.hostname}建立连接成功`)
      socket.setNoDelay.bind(socket); // 启用/禁用Nagle算法。传递true的noDelay或不传递参数将禁用Nagle算法套接字。传递false为noDelay使Nagle算法。
      // nvt协商窗口大小
      // socket.write(Buffer.from([0xff, 0xfb, 0x1f])); //will NAWS
      // socket.write(
      //   Buffer.from([0xff, 0xfa, 0x1f, 0x00, 0x50, 0xfe, 0xfe, 0xff, 0xf0])); //do NAWS
      // nvt协商echo和suppress
      socket.write(iac.dont.echo);
      socket.write(iac.do.suppress);
    });
    socket.connect(dest.port, dest.hostname);

    // 当套接字的另一端发送FIN数据包时发出，从而结束了套接字的可读端。
    socket.on('end', () => {
      console.log('--end--');
      if (interacting) {
        process.stdin.removeAllListeners('data');
        if (opts.exit) process.exit(0);
      }
    });
    socket.on('data', async chunk => {
      saved += chunk;
      let info = saved.split(/\r?\n/).pop()
      // console.log(info)
      const temp = saved.replace(/\r\n/, '');
      if (seq.length == 0) {
        endSocket(socket);
        return;
      }
      if (!seq[index].timeout) {
        // 为发送项设置超时时间
        seq[index].timeout = setTimeout(() => {
          endSocket(socket);
          return reject(
            new Error('Expect sequence timeout: ' + seq[index].expect)
          );
        }, TIMEOUT);
      }
      // 查看收到的数据是否满足expect
      let matched;
      if (seq[index].expect instanceof RegExp) {
        matched = seq[index].expect.test(saved);
      } else if (typeof seq[index].expect === 'string') {
        matched = saved.indexOf(seq[index].expect) !== -1;
      } else {
        endSocket(socket);
        return reject(
          new Error('Expected a String or RegExp:' + seq[index].expect)
        );
      }
      if (matched) {
        // 匹配期待字符成功
        clearTimeout(seq[index].timeout);

        if (!temp || !saved.trim()) {
          return; // 如果收到的东西是空字符串只包含换行符的话,就直接结束
        }
        // 判断上一条命令需要是否返回错误，跳出telnet
        const x = index - 1 > 0 ? index - 1 : 0;
        if (seq[x].break && seq[x].fn) {
          const bresult = seq[x].fn(saved);
          if (!bresult.result) {
            resultArr.push(bresult.message);
            endSocket(socket);
            return resolve(resultArr);
          }
        }
        // 判断是否需要输出上一条的命令的返回结果
        if (seq[index].out) {
          const lines = [];
          saved.split(/\r?\n/).forEach(line => {
            if (line) lines.push(line);
          });
          // lines = lines.length >= 3 ? lines.slice(1, lines.length - 1) : lines;
          resultArr.push(lines.join('\n'));
        }

        if (seq[index].send) {
          count = 1;
          socket.write(seq[index].send);
        }
        index++;
        saved = '';
        if (index == seq.length) {
          endSocket(socket);
          return resolve(resultArr);
        }
      } else {
        // 若没有匹配成功，判断是否有more，发送空格翻屏
        const groups = temp.match(reg);
        const groups1 = temp.match(reg1);
        if ((groups != null && groups.length == count) || (groups1 != null && groups1.length == count)) {
          count++;
          socket.write(' ');
        }
      }
    });
  });
};
